﻿// ***********************************************************************
// Assembly         : Invisionware.API.Amazon
// Author           : Shawn Anderson (sanderson@eye-catcher.com)
// Created          : 01-10-2014
//
// Last Modified By : Shawn Anderson
// Last Modified On : 01-19-2014
// ***********************************************************************
// <copyright file="ItemDataTypes.cs" company="Invisionware">
//     Copyright (c) Invisionware. All rights reserved.
// </copyright>
// <summary></summary>
// ***********************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace Invisionware.API.Amazon
{
	/// <summary>
	/// Pulls XML data from Amazon Associates API
	/// </summary>
	public class AwsItemResultsParser
	{
		#region Public Properties
		/// <summary>
		/// No picture image
		/// </summary>
		private static string NoPicture
		{
			get
			{
				return "http://teamportfolios.com/images/no-avatar-small.png";
			}
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Parses the XML data based on the location of an XML file
		/// </summary>
		/// <param name="options">The options.</param>
		/// <param name="data">The data.</param>
		/// <returns>List{AwsItemLookupResult}.</returns>
		public static List<AwsItemLookupResult> ParseItemLookup(AwsCommonOptions options, XElement data)
		{
			//Query Amazon's XML file for products
			try
			{
				XNamespace ns = options.AwsNameSpace;

				var tags = data;

				var groups = (from item in tags.Descendants(ns + "Item") // Return all nodes with the word "Item" in it
							  let itemAttributes = item.Element(ns + "ItemAttributes") //In each Item node, get the "ItemAttributes" node
							  let offerAttributes = item.Element(ns + "OfferSummary") //Get the Offer Summary Node
							  let mediumImageAttributes = item.Element(ns + "MediumImage")
							  let smallImageAttributes = item.Element(ns + "SmallImage")
							  let largeImage = item.Element(ns + "LargeImage")

							  //Notice how I get each picture's URL here
							  let lI = largeImage != null ? ((string)largeImage.Element(ns + "URL")) : string.Empty
							  let mI = mediumImageAttributes != null ? ((string)mediumImageAttributes.Element(ns + "URL")) : string.Empty
							  let sI = smallImageAttributes != null ? ((string)smallImageAttributes.Element(ns + "URL")) : string.Empty
							  let lowestNewPrice = offerAttributes != null ? offerAttributes.Element(ns + "LowestNewPrice") : null //Within the Offer Summary Node, get the Lowest New Price node
							  orderby Convert.ToInt32((string)item.Element(ns + "SalesRank")) ascending

							  select new AwsItemLookupResult
							  {
								  ASIN = ((string)item.Element(ns + "ASIN")),
								  SalesRank = Convert.ToInt32((string)item.Element(ns + "SalesRank")),
								  ProductName = itemAttributes != null ? ((string)itemAttributes.Element(ns + "Title")) : string.Empty,

								  //I then check if the picture if null or empty
								  // and if null or empty, return a image saying no picture available
								  // else return the image
								  LargeProductImageUrl = (!String.IsNullOrEmpty(lI)) ? lI : NoPicture,
								  MediumProductImageUrl = (!String.IsNullOrEmpty(mI)) ? mI : NoPicture,
								  SmallProductImageUrl = (!String.IsNullOrEmpty(sI)) ? sI : NoPicture,

								  DetailPageUrl = ((string)item.Element(ns + "DetailPageURL")),
								  Manufacturer = itemAttributes != null ? ((string)itemAttributes.Element(ns + "Manufacturer")) : string.Empty,
								  ProductGroup = itemAttributes != null ? ((string)itemAttributes.Element(ns + "ProductGroup")) : string.Empty,
								  ProductPrice = ParsePrice(options, lowestNewPrice)
							  });

				if (groups.Any())
				{
					return groups.ToList();
				}

				System.Diagnostics.Trace.WriteLine("No data.");

				return null;
				//throw new Exception("No data.");
			}
			catch (NullReferenceException ex)
			{
				System.Diagnostics.Trace.WriteLine("The data has returned no results. Please check and see if you've filled out your AwsAccessKeyID and your AwsSecretAccessKey. Please also ensure that your search words are spelled correctly");
				System.Diagnostics.Trace.WriteLine(ex.ToString());

				return null;
				//throw new NullReferenceException("The data has returned no results. Please check and see if you've filled out your AwsAccessKeyID and your AwsSecretAccessKey. Please also ensure that your search words are spelled correctly");
			}
			catch (HttpException ex)
			{
				System.Diagnostics.Trace.WriteLine("An HTTP exception has occurred");
				System.Diagnostics.Trace.WriteLine(ex.ToString());

				return null;
				//throw new HttpException("An HTTP exception has occurred");
			}
			catch (Exception ex)
			{
				System.Diagnostics.Trace.WriteLine("A general error has occurred. Please ensure that the URL going into the method is correct. Check the code in the class library.");
				System.Diagnostics.Trace.WriteLine(ex.ToString());

				return null;
				//throw new Exception("A general error has occurred. Please ensure that the URL going into the method is correct. Check the code in the class library.");
			}
		}

		/// <summary>
		/// Parses data for similarity look-up, so there are no pictures
		/// </summary>
		/// <param name="options">The options.</param>
		/// <param name="data">The data.</param>
		/// <returns>List{AwsItemLookupResult}.</returns>
		public static List<AwsItemLookupResult> ParseSimilarityData(AwsCommonOptions options, XElement data)
		{
			//Query Amazon's XML file for products
			try
			{
				XNamespace ns = options.AwsNameSpace;

				var tags = data;

				var groups = (from item in tags.Descendants(ns + "Item") // Return all nodes with the word "Item" in it
							  let itemAttributes = item.Element(ns + "ItemAttributes") //In each Item node, get the "ItemAttributes" node
							  let offerAttributes = item.Element(ns + "OfferSummary") //Get the Offer Summary Node
							  let lowestNewPrice = offerAttributes != null ? offerAttributes.Element(ns + "LowestNewPrice") : null //Within the Offer Summary Node, get the Lowest New Price node
							  orderby Convert.ToInt32((string)item.Element(ns + "SalesRank")) ascending

							  select new AwsItemLookupResult
							  {
								  ASIN = ((string)item.Element(ns + "ASIN")),
								  SalesRank = Convert.ToInt32((string)item.Element(ns + "SalesRank")),
								  ProductName = itemAttributes != null ? ((string)itemAttributes.Element(ns + "Title")) : string.Empty,
								  DetailPageUrl = ((string)item.Element(ns + "DetailPageURL")),
								  Manufacturer = itemAttributes != null ? ((string)itemAttributes.Element(ns + "Manufacturer")) : string.Empty,
								  ProductGroup = itemAttributes != null ? ((string)itemAttributes.Element(ns + "ProductGroup")) : string.Empty,
								  ProductPrice = ParsePrice(options, lowestNewPrice)
							  });

				if (groups.Any())
				{
					return groups.ToList();
				}

				System.Diagnostics.Trace.WriteLine("No data.");

				return null;
				//throw new Exception("No data.");
			}
			catch (NullReferenceException ex)
			{
				System.Diagnostics.Trace.WriteLine("The data has returned no results. Please check and see if you've filled out your AwsAccessKeyID and your AwsSecretAccessKey. Please also ensure that your search words are spelled correctly");
				System.Diagnostics.Trace.WriteLine(ex.ToString());

				return null;

				//throw new NullReferenceException("The data has returned no results. Please check and see if you've filled out your AwsAccessKeyID and your AwsSecretAccessKey. Please also ensure that your search words are spelled correctly");
			}
			catch (HttpException ex)
			{
				System.Diagnostics.Trace.WriteLine("An HTTP exception has occurred");
				System.Diagnostics.Trace.WriteLine(ex.ToString());

				return null;

				//throw new HttpException("An HTTP exception has occurred");
			}
			catch (Exception ex)
			{
				System.Diagnostics.Trace.WriteLine("A general error has occurred. Please ensure that the URL going into the method is correct. Check the code in the class library.");
				System.Diagnostics.Trace.WriteLine(ex.ToString());

				return null;

				//throw new Exception("A general error has occurred. Please ensure that the URL going into the method is correct. Check the code in the class library.");
			}
		}
		#endregion Public Methods

		#region Private Methods
		/// <summary>
		/// Parses the price.
		/// </summary>
		/// <param name="options">The options.</param>
		/// <param name="priceElement">The price element.</param>
		/// <returns>System.Decimal.</returns>
		private static decimal ParsePrice(AwsCommonOptions options, XElement priceElement)
		{
			XNamespace ns = options.AwsNameSpace;

			if (priceElement == null) return (decimal)0.0;

			return Convert.ToDecimal(((string)priceElement.Element(ns + "FormattedPrice")).Replace("$", String.Empty));
		}
		#endregion Private Methods
	}
}
